#include "VulkanQueue.h"
#include "VulkanDevice.h"
#include "VulkanSemaphore.h"
#include "VulkanFence.h"
#include "VulkanCommandBuffer.h"
#include "VulkanBarriers.h"

namespace Alice
{
	VulkanQueue::VulkanQueue(
#ifdef _DEBUG
			const char * inDebugName,
#endif
			VulkanDevice* InDevice, uint32 InFamilyIndex)
    : mQueue(VK_NULL_HANDLE)
    , mFamilyIndex(InFamilyIndex)
    , mQueueIndex(0)
    , mDevice(InDevice)
    {
		mDebugName=inDebugName;
        vkGetDeviceQueue(mDevice->GetDevice(),mFamilyIndex,mQueueIndex,&mQueue);
    }
    void VulkanQueue::Submit(VulkanCommandBuffer* CmdBuffer, uint32 NumSignalSemaphores, VkSemaphore* SignalSemaphores)
	{
		VulkanFence* Fence = CmdBuffer->mFence;
		
		const VkCommandBuffer CmdBuffers[] = { CmdBuffer->GetHandle() };

		VkSubmitInfo SubmitInfo={};
		SubmitInfo.sType=VK_STRUCTURE_TYPE_SUBMIT_INFO;
		SubmitInfo.commandBufferCount = 1;
		SubmitInfo.pCommandBuffers = CmdBuffers;
		SubmitInfo.signalSemaphoreCount = NumSignalSemaphores;
		SubmitInfo.pSignalSemaphores = SignalSemaphores;

		std::vector<VkSemaphore> WaitSemaphores;
		if (CmdBuffer->mWaitSemaphores.size() > 0)
		{
			for (VulkanSemaphore* Semaphore : CmdBuffer->mWaitSemaphores)
			{
				WaitSemaphores.push_back(Semaphore->GetHandle());
			}
			SubmitInfo.waitSemaphoreCount = WaitSemaphores.size();
			SubmitInfo.pWaitSemaphores = WaitSemaphores.data();
			SubmitInfo.pWaitDstStageMask = CmdBuffer->mWaitFlags.data();
		}
		{
			vkQueueSubmit(mQueue, 1, &SubmitInfo, Fence->GetHandle());
		}

		CmdBuffer->State = VulkanCommandBuffer::EState::Submitted;
		CmdBuffer->MarkSemaphoresAsSubmitted();
		//CmdBuffer->SubmittedFenceCounter = CmdBuffer->FenceSignaledCounter;

		bool bShouldStall = false;

		if (true)//GWaitForIdleOnSubmit != 0)
		{
			CGIVulkanCommandBufferManager* CmdBufferMgr = &CmdBuffer->GetOwner()->GetMgr();

			switch(1)//GWaitForIdleOnSubmit)
			{
				default:
					// intentional fall-through
				case 1:
					bShouldStall = true;
					break;

				case 2:
					//bShouldStall = (CmdBufferMgr->HasPendingUploadCmdBuffer() && CmdBufferMgr->GetUploadCmdBuffer() == CmdBuffer);
					break;

				case 3:
					//bShouldStall = (CmdBufferMgr->HasPendingActiveCmdBuffer() && CmdBufferMgr->GetActiveCmdBufferDirect() == CmdBuffer);
					break;
			}
		}

		if (bShouldStall)
		{
			// 2000 ms timeout
			static uint64 timeOut = 2000 * 1000 * 1000;
			bool bSuccess = mDevice->GetFenceManager().WaitForFence(CmdBuffer->mFence, timeOut);
			//CmdBuffer->GetOwner()->RefreshFenceStatus();
		}

		//UpdateLastSubmittedCommandBuffer(CmdBuffer);
		CmdBuffer->RefreshFenceStatus();
		//CmdBuffer->GetOwner()->RefreshFenceStatus(CmdBuffer);

		//mDevice->GetStagingManager().ProcessPendingFree(false, false);

		// If we're tracking layouts for the queue, merge in the changes recorded in this command buffer's context
		//CmdBuffer->GetLayoutManager().TransferTo(LayoutManager);
	}
}